package com.common.spring;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Service;


/**
 * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
 * 
 * @author jfeng
 * @version 2014-03-04
 */
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
	public static final String SCOPE_SESSION = "sessionContextHolder";
	public static final String SCOPE_REQUEST = "requestContextHolder";
	public static final String SCOPE_APPLICATION = "applicationContextHolder";
	public static final String CONTEXT_HTTP_REQUEST = "httpRequest";
	public static final String CONTEXT_HTTP_SESSION = "httpSession";
	private static ApplicationContext applicationContext = null;

	private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);

	/**
	 * 取得存储在静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}
	
	/**
	 * 获取系统根目录
	 * @return
	 */
	public static String getRootRealPath(){
		String rootRealPath ="";
		try {
			rootRealPath=getApplicationContext().getResource("").getFile().getAbsolutePath();
		} catch (IOException e) {
			logger.warn("获取系统根目录失败");
		}
		return rootRealPath;
	}
	
	/**
	 * 获取资源根目录
	 * @return
	 */
	public static String getResourceRootRealPath(){
		String rootRealPath ="";
		try {
			rootRealPath=new DefaultResourceLoader().getResource("").getFile().getAbsolutePath();
		} catch (IOException e) {
			logger.warn("获取资源根目录失败");
		}
		return rootRealPath;
	}
	

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		if (name == null)
			return null;
		if (name.equalsIgnoreCase("null"))
			return null;
		return (T) getBeanByBeanIdOrClass(name, null);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T> T getBean(Class<T> requiredType) {
		List beans = SpringContextHolder.getBeansByClass(requiredType);
		if (beans == null || beans.isEmpty()) {
			return null;
		}
		return (T) beans.get(0);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		if (logger.isDebugEnabled()){
			logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
		}
		applicationContext = null;
	}

	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	public void setApplicationContext(ApplicationContext applicationContext) {
//		logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);

		if (SpringContextHolder.applicationContext != null) {
			logger.info("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
		}

		SpringContextHolder.applicationContext = applicationContext; // NOSONAR
	}

	/**
	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
	 */
	public void destroy() throws Exception {
		SpringContextHolder.clearHolder();
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
		Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
	}
	
	/**
	 * 获取Bean列表
	 * @param targetClass
	 * 		Class名称
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static List getBeansByClass(Class targetClass) {
		List ret = new ArrayList();
		if ((applicationContext == null) || (targetClass == null)) {
			return ret;
		}
		Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
				applicationContext, targetClass, true, true);

		if (beans.size() == 0) {
			logger.info("No bean of type " + targetClass.toString() + " found.");
		}
		return new ArrayList(beans.values());
	}

	/**
	 * 通过BeanId和Class名称获取Bean对象
	 * @param beanId
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static Object getBeanByBeanIdOrClass(String beanId, Class clazz) {
		if (applicationContext == null) {
			return null;
		}
		if ("null".equalsIgnoreCase(beanId)) {
			return null;
		}
		if ((beanId != null) && (applicationContext.containsBean(beanId))) {
			return applicationContext.getBean(beanId);
		}
		List l = getBeansByClass(clazz);
		if (l.size() > 0)
			return l.get(0);
		return null;
	}
	
	/**
	 * spring scope操作
	 * @param key
	 * 		键
	 * @param value
	 * 		值
	 * @param scopeBeanId
	 * 		生存周期 requestContextHolder,sessionContextHolder,applicationContextHolder
	 */
	public static void put(String key, Object value, String scopeBeanId) {
		ContextHolder contextHolder = (ContextHolder) getBean(scopeBeanId);
		if (contextHolder != null)
			contextHolder.put(key, value);
	}

	/**
	 * spring scope操作
	 * @param key
	 * 		键
	 * @param scopeBeanId
	 * 		生存周期 requestContextHolder,sessionContextHolder,applicationContextHolder
	 * @return
	 */
	public static Object get(String key, String scopeBeanId) {
		ContextHolder contextHolder = (ContextHolder) getBean(scopeBeanId);
		if (contextHolder != null)
			return contextHolder.get(key);
		return null;
	}

	/**
	 * spring scope操作
	 * @param scopeBeanId
	 * 		生存周期 requestContextHolder,sessionContextHolder,applicationContextHolder
	 */
	public static void clear(String scopeBeanId) {
		ContextHolder contextHolder = (ContextHolder) getBean(scopeBeanId);
		if (contextHolder != null)
			contextHolder.clear();
	}
}